//////////////////////////////////////////////////////////////////////////
//
// Nano Octane Plugin Dll File
//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
#include "object/NO_CModule.h"
#include "module/NO_CModule.h"
#include "archive/NO_CModule.h"
#include "type/NO_CModule.h"

//////////////////////////////////////////////////////////////////////////
#define protected friend void load(void); protected
#include "type/NO_Test.h"
#undef protected

//////////////////////////////////////////////////////////////////////////
NO_Plugin* plugin;
NO_Plugin* base;

//////////////////////////////////////////////////////////////////////////
template<class M, NO_UInt32 N, class C>
NO_IMember* nmr(M (C::*m) [N], const NO_Int8* n)
{
	return new NO_RangeMember<M,N,C >(m,n);
}

//////////////////////////////////////////////////////////////////////////
template<class M, NO_UInt32 N>
NO_IMember* nmr(M (*m) [N], const NO_Int8* n)
{
	return new NO_StaticRangeMember<M,N >(*m,n);
}

//////////////////////////////////////////////////////////////////////////
template<class T>
class IObject
{
public:
protected:
private:
};

//////////////////////////////////////////////////////////////////////////
void load(void)
{
	try
	{

		//////////////////////////////////////////////////////////////////////////
		// Base types
		//////////////////////////////////////////////////////////////////////////
	
		//////////////////////////////////////////////////////////////////////////
		base = NO_Plugin::define("NO_BaseTypes");

		//////////////////////////////////////////////////////////////////////////
		NO_BuildInType(NO_Boolean)::define("Boolean",*base).addConstructor(noMakeConstructor(NO_Boolean));
		NO_BuildInType(std::string)::define("String",*base).addConstructor(noMakeConstructor(std::string));
		NO_BuildInType(NO_UInt)::define("UInt",*base).addConstructor(noMakeConstructor(NO_UInt));
		NO_BuildInType(NO_UInt8)::define("UInt8",*base).addConstructor(noMakeConstructor(NO_UInt8));
		NO_BuildInType(NO_UInt16)::define("UInt16",*base).addConstructor(noMakeConstructor(NO_UInt16));
		NO_BuildInType(NO_UInt32)::define("UInt32",*base).addConstructor(noMakeConstructor(NO_UInt32));
		NO_BuildInType(NO_UInt64)::define("UInt64",*base).addConstructor(noMakeConstructor(NO_UInt64));
		NO_BuildInType(NO_Int)::define("Int",*base).addConstructor(noMakeConstructor(NO_Int));
		NO_BuildInType(NO_Int8)::define("Int8",*base).addConstructor(noMakeConstructor(NO_Int8));
		NO_BuildInType(NO_Int16)::define("Int16",*base).addConstructor(noMakeConstructor(NO_Int16));
		NO_BuildInType(NO_Int32)::define("Int32",*base).addConstructor(noMakeConstructor(NO_Int32));
		NO_BuildInType(NO_Int64)::define("Int64",*base).addConstructor(noMakeConstructor(NO_Int64));
		NO_BuildInType(NO_Float32)::define("Float32",*base).addConstructor(noMakeConstructor(NO_Float32));
		NO_BuildInType(NO_Float64)::define("Float64",*base).addConstructor(noMakeConstructor(NO_Float64));

		//////////////////////////////////////////////////////////////////////////
		NO_TypeImp<void,NO_VOID_TYPE,NO_NoneSizing,NO_Naming>::define("void",*base);
		NO_TypeImp<void*,NO_VOID_TYPE,NO_NoneSizing,NO_Naming>::define("void *",*base);
		NO_TypeImp<void const *,NO_VOID_TYPE,NO_NoneSizing,NO_Naming>::define("void const *",*base);

		//////////////////////////////////////////////////////////////////////////
		NO_ObjectType(NO_Object)::define("Object",*base).addConstructor(noMakeConstructor(NO_Object));
		NO_VectorType(NO_Object)::define("vector<Object>",*base).addConstructor(noMakeConstructor(std::vector<NO_Object>));
		NO_SimpleType(NO_ObjectList)& list = NO_SimpleType(NO_ObjectList)::define("ObjectList",*base);
		list.addConstructor(noMakeConstructor(NO_ObjectList));
		list.addMember(noMakeMember(&NO_ObjectList::list,"list"));
		list.addFunction(noMakeFunc1Ref<NO_ObjectList,NO_Object>(&NO_ObjectList::operator<<,"<<"));

		//////////////////////////////////////////////////////////////////////////
		// Test Plugin
		//////////////////////////////////////////////////////////////////////////
		plugin = NO_Plugin::define("NO_Plugin");

		//////////////////////////////////////////////////////////////////////////
		NO_SimpleType(Base)& bt = NO_SimpleType(Base)::define("Base",*plugin);
		bt.addConstructor(noMakeConstructor(Base));
		bt.addMember(noMakeMember(&Base::sl,"sl"));
		
		//////////////////////////////////////////////////////////////////////////
		NO_DerivedType(VirBaseL)& lt = NO_DerivedType(VirBaseL)::define("VirBaseL",*plugin);
		lt.addConstructor(noMakeConstructor(VirBaseL));
		lt.addMember(noMakeMember(&VirBaseL::slb,"slb"));
		lt.addBase(noMakeBase(Base,VirBaseL));
		
		//////////////////////////////////////////////////////////////////////////
		NO_DerivedType(VirBaseR)& rt = NO_DerivedType(VirBaseR)::define("VirBaseR",*plugin);
		rt.addConstructor(noMakeConstructor(VirBaseR));
		rt.addMember(noMakeMember(&VirBaseR::slc,"slc"));
		rt.addBase(noMakeBase(Base,VirBaseR));
		
		//////////////////////////////////////////////////////////////////////////
		NO_DerivedType(Super)& st = NO_DerivedType(Super)::define("Super",*plugin);
		st.addConstructor(noMakeConstructor(Super));
		st.addFunction(noMakeFunc1Ref<Super,Super,Super&,Super const &>(&Super::operator =,"="));
		st.addMember(noMakeMember(&Super::slmt,"slm"));
		st.addBase(noMakeBase(Base,Super));
		st.addBase(noMakeBase(VirBaseR,Super));
		st.addBase(noMakeBase(VirBaseL,Super));
		
		//////////////////////////////////////////////////////////////////////////
		NO_SimpleType(SmallMaster)& sm = NO_SimpleType(SmallMaster)::define("Master",*plugin);
		sm.addConstructor(noMakeConstructor(SmallMaster));
		sm.addFunction(noMakeFunc0(&SmallMaster::setBaseB,"setBase"));
		sm.addFunction(noMakeFunc0(&SmallMaster::setBaseL,"setLeft"));
		sm.addFunction(noMakeFunc0(&SmallMaster::setBaseR,"setRight"));
		sm.addFunction(noMakeFunc0(&SmallMaster::setBaseM,"setMi"));
		sm.addMember(noMakeMember(&SmallMaster::base,"miTest"));
		
		//////////////////////////////////////////////////////////////////////////
		NO_VectorType(Base)::define("vector<Base>",*plugin).addConstructor(noMakeConstructor(std::vector<Base>));
		NO_VectorType(Base*)::define("vector<Base>",*plugin).addConstructor(noMakeConstructor(std::vector<Base*>));
		NO_PairType(NO_UInt32,Base)::define("pair<NO_UInt32,Base>",*plugin).addConstructor(new NO_Constructor<std::pair<NO_UInt32,Base> >());
		NO_PairType(NO_UInt32,Base*)::define("pair<NO_UInt32,Base*>",*plugin).addConstructor(new NO_Constructor<std::pair<NO_UInt32,Base*> >());
		NO_MapType(NO_UInt32,Base)::define("map<NO_UInt32,Base>",*plugin).addConstructor(new NO_Constructor<std::map<NO_UInt32,Base> >());
		NO_MapType(NO_UInt32,Base*)::define("map<NO_UInt32,Base*>",*plugin).addConstructor(new NO_Constructor<std::map<NO_UInt32,Base> >());
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectType(NO_TypeObject<Super>)::define("Object<Super>",*plugin).addConstructor(noMakeConstructor(NO_TypeObject<Super>));
		
		//////////////////////////////////////////////////////////////////////////
		NO_SimpleType(FullMaster)& mt = NO_SimpleType(FullMaster)::define("FullMaster",*plugin);
		mt.addConstructor(noMakeConstructor(FullMaster));
		mt.addFunction(noMakeFunc0(&FullMaster::setNoPointer,"setNo"));
		mt.addFunction(noMakeFunc0(&FullMaster::setBaseB,"setBase"));
		mt.addFunction(noMakeFunc0(&FullMaster::setBaseL,"setLeft"));
		mt.addFunction(noMakeFunc0(&FullMaster::setBaseR,"setRight"));
		mt.addFunction(noMakeFunc0(&FullMaster::setBaseM,"setMi"));
		mt.addFunction(noMakeFunc0(&FullMaster::setIntArray,"setIntArray"));
		mt.addFunction(noMakeFunc0(&FullMaster::setValue,"setValue"));
		mt.addFunction(noMakeFunc0(&FullMaster::madePtrPtr,"made"));
		mt.addFunction(noMakeFunc0(&FullMaster::delPtrPtr,"del"));
		mt.addFunction(noMakeFunc0(&FullMaster::setDynamicBase,"dynBase"));
		mt.addFunction(noMakeFunc0(&FullMaster::setDynamicSuper,"dynSuper"));
		mt.addFunction(noMakeFunc0(&FullMaster::setSTL,"setSTL"));
		mt.addFunction(noMakeFunc0(&FullMaster::t,"t"));
		mt.addFunction(noMakeFunc0(&FullMaster::tc,"tc"));
		mt.addFunction(noMakeFunc0Ref<NO_UInt32,NO_UInt32&>(&FullMaster::tr,"tr"));
		mt.addFunction(noMakeFunc0Ref<NO_UInt32,NO_UInt32&>(&FullMaster::trc,"trc"));
		mt.addFunction(noMakeFunc1(&FullMaster::t1,"t1"));
		mt.addFunction(noMakeFunc1(&FullMaster::t1c,"t1c"));
		mt.addFunction(noMakeFunc1Ref<NO_UInt32,NO_UInt32,NO_UInt32&,NO_UInt32>(&FullMaster::t1r,"t1r"));
		mt.addFunction(noMakeFunc1Ref<NO_UInt32,NO_UInt32,NO_UInt32&,NO_UInt32>(&FullMaster::t1rc,"t1rc"));
		mt.addFunction(noMakeFunc2(&FullMaster::t2,"t2"));
		mt.addFunction(noMakeFunc2(&FullMaster::t2c,"t2c"));
		mt.addFunction(noMakeFunc2Ref<NO_UInt32,NO_UInt32,NO_UInt32,NO_UInt32&,NO_UInt32,NO_UInt32>(&FullMaster::t2r,"t2r"));
		mt.addFunction(noMakeFunc2Ref<NO_UInt32,NO_UInt32,NO_UInt32,NO_UInt32&,NO_UInt32,NO_UInt32>(&FullMaster::t2rc,"t2rc"));
		mt.addFunction(noMakeFunc1(&FullMaster::setValueTo,"setValueTo"));/**/
	//	mt.addMember(noMakeMember((int FullMaster::*)&FullMaster::cInt,"cInt"));
	//	mt.addMember(noMakeMember((int* FullMaster::*)&FullMaster::cIntPtr,"cIntPtr"));
	//	mt.addMember(noMakeMember(&FullMaster::noObject,"object"));
	//	mt.addMember(noMakeMember(&FullMaster::noObjectToSame,"objectIdent"));
	//	mt.addMember(noMakeMember(&FullMaster::value,"intValue"));
	//	mt.addMember(noMakeMember(&FullMaster::ptrToInt,"ptrToInt"));
	//	mt.addMember(noMakeMember(&FullMaster::ptr,"ptr1"));
	//	mt.addMember(noMakeMember(&FullMaster::ptrToSame,"ptr2"));
	//	mt.addMember(noMakeMember(&FullMaster::ptrIntoArray,"ptrInto"));
	//	mt.addMember(noMakeRange<NO_UInt32, 2>(&FullMaster::intArray,"intArray"));
	//	mt.addMember(noMakeRange<NO_UInt32, 2>(&FullMaster::sIntArr,"sIntArray"));
	//	mt.addMember(noMakeRange<Base, 2>(&FullMaster::objArray,"objArray"));
		mt.addMember(noMakeRange<Base*, 2>(&FullMaster::allArray,"ptrArray"));
	//	mt.addMember(noMakeMember(&FullMaster::vecOfBase,"vector of base"));
	//	mt.addMember(noMakeMember(&FullMaster::vecOfPtr,"vector of pointers"));
	//	mt.addMember(noMakeMember(&FullMaster::mapOfBase,"map of BASE"));
	//	mt.addMember(noMakeMember(&FullMaster::mapOfPtr,"map of ptr"));/**/
	}
	catch (std::bad_cast& e)	{std::cout<<e.what()<<std::endl;}
	catch (std::bad_typeid& e)	{std::cout<<e.what()<<std::endl;}
	catch (std::exception& e)	{std::cout<<e.what()<<std::endl;}
	catch (...)					{std::cout<<"plugin load failed"<<std::endl;}
}

//////////////////////////////////////////////////////////////////////////
void unload(void)
{
	delete plugin;
	delete base;
}

//////////////////////////////////////////////////////////////////////////
extern "C"__declspec(dllexport) void loadPlugin(void)
{
	load();
}

//////////////////////////////////////////////////////////////////////////
extern "C"__declspec(dllexport) int* toKill(void)
{
	return new int[100];
}

//////////////////////////////////////////////////////////////////////////
extern "C"__declspec(dllexport) void testPlugin(void)
{
	try
	{
		//////////////////////////////////////////////////////////////////////////
		NO_Object o1("FullMaster");

		//////////////////////////////////////////////////////////////////////////
		// function time test
		//////////////////////////////////////////////////////////////////////////
	
		//////////////////////////////////////////////////////////////////////////
		int cyc = 1000;
		int num = 0;
		int time = 0;
		double ref = 0;
		FullMaster master;
		
		//////////////////////////////////////////////////////////////////////////
		NO_ObjectList list;
		NO_Object p("UInt32");
		list<<p;

		//////////////////////////////////////////////////////////////////////////
		// warm up
		//////////////////////////////////////////////////////////////////////////
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc){master.t2(1,1);}

		//////////////////////////////////////////////////////////////////////////
		// function two parameter
		//////////////////////////////////////////////////////////////////////////

		//////////////////////////////////////////////////////////////////////////
		list<<p;

		//////////////////////////////////////////////////////////////////////////
		std::cout<<std::endl<<"Function two parameters"<<std::endl;

		//////////////////////////////////////////////////////////////////////////
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			master.t2(1,1);
			++num;
		}
		ref = num;
		std::cout<<GetTickCount()-time<<" reference two \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			o1.call("t2",list);
			++num;
		}
		std::cout<<GetTickCount()-time<<" search call two \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		const NO_IFunction& f2 = *o1.getType().findFunction("t2",NO_TypeList()<<NO_TypeID<NO_UInt32>::type()<<NO_TypeID<NO_UInt32>::type());
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f2(o1,list);
			++num;
		}
		std::cout<<GetTickCount()-time<<" direct call two \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		NO_IFuncBind& f2b = (*(o1.function("t2",NO_TypeList()<<NO_TypeID<NO_UInt32>::type()<<NO_TypeID<NO_UInt32>::type()).bind(o1)));
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f2b(list);
			++num;
		}
		std::cout<<GetTickCount()-time<<" bind call two \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		NO_IFuncObject& f2o = (*(o1.function("t2",NO_TypeList()<<NO_TypeID<NO_UInt32>::type()<<NO_TypeID<NO_UInt32>::type()).object(o1,list)));
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f2o();
			++num;
		}
		std::cout<<GetTickCount()-time<<" object call two \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		// function one parameter
		//////////////////////////////////////////////////////////////////////////

		//////////////////////////////////////////////////////////////////////////
		list.list.clear();
		list<<p;

		//////////////////////////////////////////////////////////////////////////
		std::cout<<std::endl<<"Function one parameter"<<std::endl;

		//////////////////////////////////////////////////////////////////////////
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			master.t1(1);
			++num;
		}
		ref = num;
		std::cout<<GetTickCount()-time<<" reference one \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			o1.call("t1",list);
			++num;
		}
		std::cout<<GetTickCount()-time<<" search call one \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		const NO_IFunction& f1 = *o1.getType().findFunction("t1",NO_TypeList()<<NO_TypeID<NO_UInt32>::type());
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f1(o1,list);
			++num;
		}
		std::cout<<GetTickCount()-time<<" direct call one \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		NO_IFuncBind& f1b = (*(o1.function("t1",NO_TypeList()<<NO_TypeID<NO_UInt32>::type()).bind(o1)));
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f1b(list);
			++num;
		}
		std::cout<<GetTickCount()-time<<" bind call one \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		NO_IFuncObject& f1o = (*(o1.function("t1",NO_TypeList()<<NO_TypeID<NO_UInt32>::type()).object(o1,list)));
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f1o();
			++num;
		}
		std::cout<<GetTickCount()-time<<" object call one \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		// function no parameter
		//////////////////////////////////////////////////////////////////////////
		
		//////////////////////////////////////////////////////////////////////////
		std::cout<<"Function zero parameters"<<std::endl;

		//////////////////////////////////////////////////////////////////////////
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			master.t();
			++num;
		}
		ref = num;
		std::cout<<GetTickCount()-time<<" reference zero \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			o1.call("t");
			++num;
		}
		std::cout<<GetTickCount()-time<<" search call zero \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		const NO_IFunction& f0 = *o1.getType().findFunction("t",NO_TypeList::empty);
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f0(o1,NO_ObjectList::empty);
			++num;
		}
		std::cout<<GetTickCount()-time<<" direct call zero \t : "<<num<<"\t factor: "<<ref/num<<std::endl;

		//////////////////////////////////////////////////////////////////////////
		NO_IFuncBind& f0b = (*(o1.function("t",NO_TypeList::empty).bind(o1)));
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f0b(NO_ObjectList::empty);
			++num;
		}
		std::cout<<GetTickCount()-time<<" bind call zero \t : "<<num<<"\t factor: "<<ref/num<<std::endl;
		
		//////////////////////////////////////////////////////////////////////////
		NO_IFuncObject& f0o = (*(o1.function("t",NO_TypeList::empty).object(o1,NO_ObjectList::empty)));
		num = 0;
		time = GetTickCount();
		while (GetTickCount()-time<cyc)
		{
			f0o();
			++num;
		}
		std::cout<<GetTickCount()-time<<" object call zero \t : "<<num<<"\t factor: "<<ref/num<<std::endl;

		//////////////////////////////////////////////////////////////////////////
		//Serialize test
		//////////////////////////////////////////////////////////////////////////
		std::cout<<"----------------------"<<std::endl;
		std::cout<<"|Begin serialize test|"<<std::endl;
		std::cout<<"----------------------"<<std::endl;
		NO_ArchiveTxt at;
		NO_ArchiveCout co;
		NO_Archivest st;
		
		o1.call("setLeft");
		o1.call("setBase");
		o1.call("setIntArray");
		o1.call("setValue");
		o1.call("made");
		o1.call("setSTL");
		o1.call("setNo");
		
		FullMaster* m = noGetData<FullMaster>(o1);
		
		std::cout<<"1-----------------------------1"<<std::endl;
		at<<o1;
		co<<o1;
		at.reset();
		
		std::cout<<"1-----------------------------2"<<std::endl;
		at>>o1;
		co<<o1;
		at.reset();
		
		std::cout<<"1-----------------------------3"<<std::endl;
		at>>o1;
		co<<o1;
		at.reset();

		//////////////////////////////////////////////////////////////////////////
/*		num = 1000;
		time = GetTickCount();
		for (i = 0; i < num ; i++)
		{
			at<<o1;
			at.reset();
		}
		std::cout<<GetTickCount()-time<<"\t : "<<num<<std::endl;*/
		
		std::cout<<"--------------------"<<std::endl;
		std::cout<<"|End serialize test|"<<std::endl;
		std::cout<<"|    successful    |"<<std::endl;
		std::cout<<"--------------------"<<std::endl;
	}
	catch (std::bad_cast& e)	{std::cout<<e.what()<<std::endl;}
	catch (std::bad_typeid& e)	{std::cout<<e.what()<<std::endl;}
	catch (std::exception& e)	{std::cout<<e.what()<<std::endl;}
	catch (...)					{std::cout<<"plugin test failed"<<std::endl;}
}

//////////////////////////////////////////////////////////////////////////
extern "C"__declspec(dllexport) void unloadPlugin(void)
{
	try{unload();}
	catch (std::bad_cast& e)	{std::cout<<e.what()<<std::endl;}
	catch (std::bad_typeid& e)	{std::cout<<e.what()<<std::endl;}
	catch (std::exception& e)	{std::cout<<e.what()<<std::endl;}
	catch (...)					{std::cout<<"plugin unload failed"<<std::endl;}
}
